package com.geline.mybatisplus.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.geline.cloud.util.StringUtils;
import com.geline.mybatisplus.annotation.UniqueKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.jdbc.core.JdbcTemplate;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author mx
 * @date 2025/8/20
 */
@Slf4j
public class UniqueKeyUtil {

    public static void validUniqueKey(Object object){
        UniqueKey[] list = object.getClass().getAnnotationsByType(UniqueKey.class);
        if (list != null && list.length>0) {
            TableName annotation = object.getClass().getAnnotation(TableName.class);
            if(annotation == null){
                annotation = object.getClass().getSuperclass().getAnnotation(TableName.class);
            }
            if(annotation != null){
                for (UniqueKey uniqueKey : list){
                    validUniqueKey(uniqueKey, annotation.value(), object);
                }
            }else {
                log.warn("can not find @TableName on = {}", object.getClass());
            }
        }
    }

    public static void validUniqueKey(UniqueKey index, String table, Object parameter){
        //主键
        String primaryKey = "id";
        Object idValue = null;
        String delKey = null;
        String delValue = "0";
        List<Field> fieldList = new ArrayList<>();
        Class<?> superclass = parameter.getClass().getSuperclass();
        if(superclass!=null){
            Field[] fields = superclass.getDeclaredFields();
            fieldList.addAll(Arrays.asList(fields));
        }
        Field[] fields = parameter.getClass().getDeclaredFields();
        fieldList.addAll(Arrays.asList(fields));
        for (Field field : fieldList){
            TableId tableId = field.getAnnotation(TableId.class);
            if(tableId!=null){
                primaryKey = tableId.value();
                idValue = BeanMap.create(parameter).get(field.getName());
            }
            TableLogic tableLogic = field.getAnnotation(TableLogic.class);
            if(tableLogic!=null){
                Class<?> type = field.getType();
                if(type==Long.class || type==long.class || type==Integer.class || type==int.class){
                    delValue = tableLogic.value();
                }else {
                    delValue = "'"+tableLogic.value()+"'";
                }
                TableField tableField = field.getAnnotation(TableField.class);
                delKey = tableField.value();
            }
        }
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("select count(*) from %s where 1=1", table));
        if(idValue != null){
            sb.append(String.format(" and %s!=%s", primaryKey, StringUtils.quotaMark(idValue)));
        }
        if(delKey != null){
            sb.append(String.format(" and %s=%s", delKey, delValue));
        }
        AtomicReference<Boolean> handle = new AtomicReference<>(false);
        String columns = index.value();
        Arrays.asList(columns.split(",")).forEach(column -> {
            String fieldName = StrUtil.toCamelCase(column);
            String columnName = StrUtil.toUnderlineCase(column);
            Object value = BeanMap.create(parameter).get(fieldName);
            if(!StrUtil.isBlankIfStr(value)){
                handle.set(true);
                String valueStr = StringUtils.quotaMark(value);
                sb.append(String.format(" and %s=%s", columnName, valueStr));
            }
        });
        //只有唯一字段有值时才检验
        if(handle.get()){
            Long number = SpringUtil.getBean(JdbcTemplate.class).queryForObject(sb.toString(), Long.class);
            if(number!=null && number>0){
                throw new RuntimeException(index.errorMsg());
            }
        }
    }
}
